package com.example.oss.Interceptor;

import com.alibaba.fastjson.JSON;
import com.example.oss.annotation.RefreshLimit;
import com.example.oss.entity.Result;
import com.example.oss.entity.ResultEnum;
import com.example.oss.entity.Student;
import com.example.oss.util.RedisKeyUtil;
import com.example.oss.util.UserContextHolder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.concurrent.TimeUnit;

/**
 * 接口防刷拦截器
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class RefreshLimitInterceptor implements HandlerInterceptor {

    private final RedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            RefreshLimit refreshLimit = handlerMethod.getMethodAnnotation(RefreshLimit.class);
            if (refreshLimit != null) {
                int maxCount = refreshLimit.maxCount();
                int second = refreshLimit.second();
                Student student = UserContextHolder.getUser();

                //使用uid+上请求uri作为key, 防止同一个用户多次重复点击刷新同一个请求
                String accessLimitKey = RedisKeyUtil.getAccessLimitKey(request.getRequestURI(), student.getId());

                Integer count = (Integer)redisTemplate.opsForValue().get(accessLimitKey);
                if (count == null) redisTemplate.opsForValue().set(accessLimitKey, 1, second, TimeUnit.SECONDS);
                //当在设定好的时间（key的过期时间）内，点击次数达到设定的最大次数时，直接返回提示信息
                else if (count <= maxCount) redisTemplate.opsForValue().increment(accessLimitKey);
                else {
                    String xRequestedWith = request.getHeader("x-requested-with");
                    if ("XMLHttpRequest".equals(xRequestedWith)) {
                        response.setContentType("application/json");
                        response.setCharacterEncoding("UTF-8");
                        PrintWriter writer = response.getWriter();
                        writer.write(JSON.toJSONString(Result.failure(ResultEnum.LIMIT)));
                        writer.flush();
                        writer.close();
                    } else {
                        response.sendRedirect(request.getContextPath() + "/400");
                    }
                    log.info("防刷。。。。。");
                    return false;
                }
            }
        }
        return true;
    }
}
